﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Reflection;
using System.ComponentModel;

namespace NPSoft.Ferrero.Framework.Utility
{
    /// <summary>
    /// 反射常用操作帮助类。
    /// </summary>
    public class ReflectionHelper
    {

        private static List<NamespaceInfo> namespacesList;
        private static List<Type> typesList;
        private static readonly object syncNS = new object();
        private static readonly object syncTypes = new object();

        /// <summary>
        /// 取得当前应用程序所有程序集定义的类型
        /// </summary>
        public static List<Type> Types
        {
            get
            {
                lock (syncTypes)
                {
                    if (typesList == null)
                    {
                        typesList = new List<Type>();
                        Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
                        foreach (Assembly assembly in assemblies)
                        {
                            Type[] types = assembly.GetTypes();
                            foreach (Type type in types)
                            {
                                if (type.IsPublic || (type.IsNested && !type.IsNestedPrivate))
                                {
                                    typesList.Add(type);
                                }
                            }
                        }
                    }
                    return typesList;
                }
            }
        }

        /// <summary>
        /// 取得命名空间列表
        /// </summary>
        public static List<NamespaceInfo> Namespaces
        {
            get
            {
                lock (syncNS)
                {
                    if (namespacesList == null)
                    {
                        namespacesList = new List<NamespaceInfo>();
                        foreach (Type type in Types)
                        {
                            if (!string.IsNullOrEmpty(type.Namespace))
                            {
                                NamespaceInfo _namespace = NamespaceInfo.AddType(type);
                                if (!namespacesList.Contains(_namespace))
                                {
                                    namespacesList.Add(_namespace);
                                }
                            }
                        }
                    }
                    return namespacesList;
                }
            }
        }

        /// <summary>
        /// 根据属性名称获取对象的该属性值
        /// </summary>
        /// <param name="value">对象</param>
        /// <param name="property">属性名称</param>
        /// <returns>属性值</returns>
        public static object GetObjectPropertyValue(object value, string property)
        {
            PropertyDescriptor objDesc = TypeDescriptor.GetProperties(value)[property];
            if (objDesc != null)
            {
                return objDesc.GetValue(value);
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// 获得对象的属性列表
        /// </summary>
        /// <param name="value">对象</param>
        /// <returns>属性列表</returns>
        public static List<string> GetObjectPropertyList(object value)
        {
            List<string> props = new List<string>();
            PropertyDescriptorCollection colDesc = TypeDescriptor.GetProperties(value);
            foreach (PropertyDescriptor objDesc in colDesc)
            {
                props.Add(objDesc.Name);
            }
            return props;
        }

        /// <summary>
        /// Get a Property value from a Type. 
        /// </summary>
        /// <typeparam name="X">The Type</typeparam>
        /// <typeparam name="T">The Type of Property to return</typeparam>
        /// <param name="name">The name of the Property to get.</param>
        /// <returns>A Function delegate</returns>
        public static Func<X, T> GetProperty<X, T>(string name)
        {
            ParameterExpression parameter = Expression.Parameter(typeof(X), "obj");
            MemberExpression property = Expression.Property(parameter, name);
            return (Func<X, T>)Expression.Lambda(typeof(Func<X, T>), property, parameter).Compile();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="property"></param>
        /// <returns></returns>
        public static object GetDefaultValue(PropertyInfo property)
        {
            object[] att = property.GetCustomAttributes(typeof(DefaultValueAttribute), false);
            if (att.Length > 0)
                return ((DefaultValueAttribute)att[0]).Value;
            else
                return string.Empty;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsTypeOf(Object obj, Type type)
        {
            return IsTypeOf(obj, type.FullName, false);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="type"></param>
        /// <param name="shallow"></param>
        /// <returns></returns>
        public static bool IsTypeOf(Object obj, Type type, bool shallow)
        {
            return IsTypeOf(obj, type.FullName, shallow);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="typeFullName"></param>
        /// <returns></returns>
        public static bool IsTypeOf(Object obj, string typeFullName)
        {
            return IsTypeOf(obj, typeFullName, false);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="typeFullName"></param>
        /// <param name="shallow">浅表匹配</param>
        /// <returns></returns>
        public static bool IsTypeOf(Object obj, string typeFullName, bool shallow)
        {
            if (obj != null)
            {
                if (shallow)
                {
                    return obj.GetType().FullName.Equals(typeFullName);
                }
                else
                {
                    Type type = obj.GetType();
                    string fullName = type.FullName;

                    while (!fullName.Equals("System.Object"))
                    {
                        if (fullName.Equals(typeFullName))
                        {
                            return true;
                        }
                        type = type.BaseType;
                        fullName = type.FullName;
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="methodInfo"></param>
        /// <param name="attributeType"></param>
        /// <param name="attributeName"></param>
        /// <returns></returns>
        public static bool IsAppliedWith(MethodInfo methodInfo, Type attributeType, string attributeName)
        {
            return methodInfo.GetCustomAttributes(attributeType, false).ToString().Contains(attributeName);
        }

    }

    /// <summary>
    /// 
    /// </summary>
    public class NamespaceInfo
    {
        private readonly string namespaceName;
        private readonly List<Type> namespaceTypes = new List<Type>();
        private static readonly Dictionary<string, NamespaceInfo> namespaces = new Dictionary<string, NamespaceInfo>();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="namespaceName"></param>
        public NamespaceInfo(string namespaceName)
        {
            this.namespaceName = namespaceName;
        }

        /// <summary>
        /// 
        /// </summary>
        public string NamespaceName
        {
            get
            {
                return namespaceName;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public List<Type> NamespaceTypes
        {
            get
            {
                return namespaceTypes;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static NamespaceInfo AddType(Type type)
        {
            lock (namespaces)
            {
                NamespaceInfo _namespace;
                if (!namespaces.TryGetValue(type.Namespace, out _namespace))
                {
                    _namespace = new NamespaceInfo(type.Namespace);
                    namespaces.Add(type.Namespace, _namespace);
                }
                if (!_namespace.namespaceTypes.Contains(type))
                {
                    _namespace.namespaceTypes.Add(type);
                }
                return _namespace;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static NamespaceInfo GetByName(string name)
        {
            NamespaceInfo _namespace;
            if (namespaces.TryGetValue(name, out _namespace))
            {
                return _namespace;
            }
            return null;
        }

    }
}
